package com.mairuide.datalog;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.Column;

import com.mairuide._frame.utils.StringUtils;

/**
 * 通道日志封装类
 * @author mh
 *
 */
public class ParseAnnotation {
	
	/**
	 * 通过新老对象封装日志信息（DataOperationDetailLog）
	 * @param newObj
	 * @param oldObj
	 * @return
	 * @throws Exception
	 */
	public static List<DataOperationDetailLog> renderingChannelLog(Object newObj, Object oldObj) throws Exception {
		List<DataOperationDetailLog> result = new LinkedList<DataOperationDetailLog>();
		/* 找到类中添加注解的属性数组 */
		List<Field> fs = findClassHaveAnno(newObj.getClass());
		
		/* 得到属性对应的两个值（新值和旧值）*/
		for (Field field : fs) {
			/* 获取这个属性的新旧两个值， [0] 表示新值， [1] 表示旧值  */
			Object[] values = getNewValueAndOldValue(field, newObj, oldObj);
			if(null == values[0] && null == values[1]) {
				continue;
			}
			if (values[0] instanceof String) {
				String str0 = (String) values[0];
				String str1 = (String) values[1];
				if(StringUtils.isEmpty(str0) && StringUtils.isEmpty(str1)) {
					continue;
				}
			}
			/* 判断修改新值与旧值是否相同 */
			if (!values[0].equals(values[1])) {
				/* 封装一个ChannelLog */
				DataOperationDetailLog dodl = encapsulationChannelLog(field, values[0], values[1]);
				result.add(dodl);
			}
		}
		return result;
	}
	
	/**
	 * 获取添加注解的属性数组
	 * @param clazz
	 * @return
	 */
	private static List<Field> findClassHaveAnno(Class<?> clazz) {
		List<Field> fieldList = new LinkedList<Field>();
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			//判断该属性是否包含字段名称注解
			boolean fieldHasAnno = field.isAnnotationPresent(LogFieldName.class);
			if (fieldHasAnno) {
				fieldList.add(field);
			}
		}
		return fieldList;
	}
	
	/**
	 * 获取这个属性的新旧两个值， [0] 表示新值， [1] 表示旧值
	 * @param field
	 * @param newObj
	 * @param oldObj
	 * @return
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 */
	private static Object[] getNewValueAndOldValue(Field field, Object newObj, Object oldObj) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
		String fieldName = field.getName();
		String methodName = String.format("get%s", captureName(fieldName));
		/* 得到get方法对象 */
		Method getNewChannelMethod1 = newObj.getClass().getMethod(methodName);
        Object newValue = getNewChannelMethod1.invoke(newObj);
        Method getOldChannelMethod = oldObj.getClass().getMethod(methodName);//得到方法对象
        Object oldValue = getOldChannelMethod.invoke(oldObj);//调用借钱方法，得到返回值
		return new Object[] {newValue, oldValue};
	}
	
    
	/**
	 * 封装channelLog对象
	 * @param field
	 * @param newValue
	 * @param oldValue
	 * @return
	 */
	private static DataOperationDetailLog encapsulationChannelLog(Field field, Object newValue, Object oldValue) {
		LogFieldName logField = field.getAnnotation(LogFieldName.class);
		Column columnName = field.getAnnotation(Column.class);
		String fieldAnnoName = logField.fieldName();
		String tableColumn = columnName.name();
		DataOperationDetailLog dodl = new DataOperationDetailLog();
		dodl.setField(tableColumn);
		dodl.setFieldName(fieldAnnoName);
		if(logField.hideValue()) {
			dodl.setNewValue("******");
			dodl.setOldValue("******");
		}else {
			if (newValue instanceof java.util.Date) {
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				dodl.setNewValue(sdf.format(newValue));
				dodl.setOldValue(oldValue == null ? null : sdf.format(oldValue));
			} else {
				dodl.setNewValue(newValue.toString());
				dodl.setOldValue(oldValue == null ? null : oldValue.toString());
			}
		}
		return dodl;
	}

	 /**
     * 获取get方法名
     * @param name
     * @return
     */
    private static String captureName(String name) {
        char[] cs=name.toCharArray();
        cs[0]-=32;
        return String.valueOf(cs);
    }
    /*
    public static void main(String[] args) throws Exception {
		Channel newChannel = new Channel();
		newChannel.setCompanyName("aa");
		newChannel.setChannelNum("11");
		Channel oldChannel = new Channel();
		
		oldChannel.setCompanyName("bb");
		oldChannel.setChannelNum("22");
		List<DataOperationDetailLog> cl = renderingChannelLog(newChannel, oldChannel);
		for(DataOperationDetailLog log : cl) {
			System.out.println("字段："+log.getField());
			System.out.println("字段名："+log.getFieldName());
			System.out.println("新值："+log.getNewValue());
			System.out.println("旧值："+log.getOldValue());
		}
		
	}
    */
}
